<template>
    <!-- 单根 -->
    <div>
        <div v-if="pageMode=='list'">
            <el-row>
                <div style="width: 200px; margin-right: 10px">
                    <el-input v-model="searchStr" @blur="loadArticles(true)" clearable>
                        <template #prepend>查询</template>
                    </el-input>
                </div>
                <div class="flex">
                    <el-tag v-for="tag in searchTags" :key="tag" closable
                            @close="closeSearchTag(tag)" :color="stringToColor(tag)">
                        {{ tag }}
                    </el-tag>
                    <el-input
                        v-if="searchTagInputVisible"
                        ref="searchTagInputRef"
                        v-model="searchTagInputValue"
                        size="small"
                        @keyup.enter="searchTagInputConfirm"
                        @blur="searchTagInputConfirm"
                    />
                    <el-button v-else @click="showSearchTagInput">
                        + 搜索标签
                    </el-button>
                    <el-button v-show="searchTags.length>0" @click="clearSearchTag">
                        清空标签
                    </el-button>
                </div>
                <div style="flex-grow: 1;"></div>
                <el-radio-group v-model="listMode" @change="listModeChange" style="margin: 0 10px;">
                    <el-radio-button label="all" value="all">全部</el-radio-button>
                    <el-radio-button label="mine" value="mine">我的</el-radio-button>
                    <el-radio-button label="lock" value="lock" v-if="checkPermission('article:lock')">已锁定
                    </el-radio-button>
                    <el-badge :value="draftCount" :hidden="draftCount==0">
                        <el-radio-button label="draft" value="draft" v-if="checkPermission('article:write')">草稿
                        </el-radio-button>
                    </el-badge>
                </el-radio-group>
                <el-button @click="addArticle" type="primary" plain :icon="EditIcon"
                           v-if="checkPermission('article:write')" style="margin: 0 10px;">写文章
                </el-button>
            </el-row>
            <el-table :data="articles" stripe v-loading="articlesLoading">
                <el-table-column prop="title" label="标题" width="300px">
                    <template #default="data">
                        <el-button type="primary" plain @click="openDetail(data.row)" link truncated>
                            {{ data.row.title }}
                        </el-button>
                        <el-tag v-for="tag in data.row.tagList" :color="stringToColor(tag)"
                                @click="addSearchTag(tag)">
                            {{ tag }}
                        </el-tag>
                    </template>
                </el-table-column>
                <el-table-column prop="writerName" label="作者" width="200px"/>
                <el-table-column prop="publishTime" label="发布时间"/>
            </el-table>
            <!-- 分页管理 -->
            <el-pagination :current-page="currentPage" :page-size="pageSize" :page-sizes="[5, 10, 20, 100]"
                           :pager-count="10"
                           :total="totalCount" layout="total, sizes, prev, pager, next" @size-change="pageSizeChange"
                           @current-change="currentPageChange"/>
        </div>
        <!-- 预览 -->
        <div style="text-align: left" v-if="pageMode=='detail'">
            <el-page-header @back="closeDetail" title="返回">
                <template #content>
                    <span class="text-large font-600 mr-3">文章详情</span>
                </template>
                <template #extra>
                    <div class="flex items-center">
                        <el-button type="primary" plain
                                   v-if="checkPermission('article:write') && checkWriter(articleDetail.writerId)"
                                   @click="editArticle">
                            编辑
                        </el-button>
                        <el-button type="warning" plain
                                   v-if="checkPermission('article:lock')"
                                   @click="lockArticle">
                            {{ articleDetail.isLock ? '解锁' : '锁定' }}
                        </el-button>
                        <el-button type="danger" plain
                                   v-if="checkPermission('article:write') && checkWriter(articleDetail.writerId)"
                                   @click="removeArticle">
                            删除
                        </el-button>
                    </div>
                </template>
            </el-page-header>
            <el-form label-width="auto" label-positon="right" :model="articleDetail">
                <el-form-item label="标题">
                    <el-text>{{ articleDetail.title }}</el-text>
                </el-form-item>
                <el-form-item label="标签">
                    <el-tag v-for="tag in articleDetail.tagList" :color="stringToColor(tag)">
                        {{ tag }}
                    </el-tag>
                </el-form-item>
                <el-form-item label="发布时间" v-if="!!articleDetail.publishTime">
                    <el-text>{{ articleDetail.publishTime }}</el-text>
                </el-form-item>
            </el-form>
            <v-md-preview :text="articleDetail.content"></v-md-preview>
        </div>
        <!-- 添加/编辑 -->
        <div style="text-align: left" v-if="pageMode=='edit'||pageMode=='add'">
            <el-page-header @back="closeEdit" title="返回">
                <template #content>
                    <span>{{ pageMode == 'add' ? '添加文章' : '编辑文章' }}</span>
                </template>
                <template #extra>
                    <div class="flex items-center">
                        <el-button @click="publishArticle" type="primary" plain
                                   v-if="pageMode=='add'&&checkPermission('article:write')">发布并返回
                        </el-button>
                        <el-button @click="publishArticle" type="primary" plain
                                   v-if="pageMode=='edit'&&checkPermission('article:write')&&!articleDetailEdit.isPublish">
                            发布
                        </el-button>
                        <el-button type="danger" plain
                                   v-if="checkPermission('article:write') && checkWriter(articleDetail.writerId)"
                                   @click="removeArticle">
                            删除
                        </el-button>
                    </div>
                </template>
            </el-page-header>
            <el-form label-width="auto" label-positon="right" :model="articleDetailEdit"
                     :rules="articleDetailEditRules" ref="articleDetailEditRef">
                <el-form-item label="标题" prop="title">
                    <el-input placeholder="请输入标题" v-model="articleDetailEdit.title">
                    </el-input>
                </el-form-item>
                <el-form-item label="标签" prop="tags">
                    <div>
                        <el-tag v-for="tag in articleDetailEdit.tagList" :key="tag" closable
                                :color="stringToColor(tag)" @close="closeEditTag(tag)">
                            {{ tag }}
                        </el-tag>
                        <el-input
                            v-if="editTagInputVisible"
                            ref="editTagInputRef"
                            v-model="editTagInputValue"
                            size="small"
                            @keyup.enter="editTagInputConfirm"
                            @blur="editTagInputConfirm"
                        />
                        <el-button v-else @click="showEditTagInput">
                            + 标签
                        </el-button>
                    </div>
                </el-form-item>
            </el-form>
            <v-md-editor v-model="articleDetailEdit.content" height="800px" @save="saveArticle"></v-md-editor>
        </div>
    </div>
</template>

<script setup lang="ts">

import {nextTick, onMounted, ref,} from "vue";
import {checkPermission} from '../assets/ts/permission-util'
import {ElInput, ElMessage, ElMessageBox, FormInstance, FormRules} from "element-plus"
import {Edit as EditIcon} from '@element-plus/icons-vue'
import {stringToColor} from "../assets/ts/common-util.ts";
import {myAxios} from "../assets/ts/my-axios.ts";
import {useLoginStore} from "../assets/ts/login.ts";


// 生命周期 - 挂载
onMounted(() => {
    loadDraftCount()
    loadArticles(true)
})

// 当前页面模式
const pageMode = ref<'list' | 'detail' | 'add' | 'edit'>('list')

// ====================================== 定义 ===========================================

// 文章信息
interface ArticleInfo {
    id: number
    title: string
    tagList: Array<string>
    writerId: number
    writerName: string
    publishTime: string
}

// 文章详情
interface ArticleDetail {
    id: number
    title: string
    tagList: Array<string>
    writerId: number
    writerName: string
    publishTime: string
    content: string
    html?: string
    // 是否已发布
    isPublish: boolean
    // 是否锁定
    isLock: boolean
    // 最近保存时间
    lastSaveTime?: string
}

const emptyArticleDetail: ArticleDetail = {
    content: "",
    id: 0,
    isLock: false,
    isPublish: false,
    publishTime: "",
    tagList: [],
    title: "",
    writerId: 0,
    writerName: ""

}

// ====================================== 文章列表 ===========================================

// 分页数据
const currentPage = ref(0)
const pageSize = ref(20)
const totalCount = ref(0)
const articlesLoading = ref(false)
const listMode = ref<'all' | 'mine' | 'draft' | 'lock'>('all')
const draftCount = ref(0)
const articles = ref<Array<ArticleInfo>>([])

// 打开文章
function openDetail(info: ArticleInfo) {
    myAxios.get('/article/detail', {params: {id: info.id}})
        .then((response: any) => {
            if (response.data.code == 0) {
                articleDetail.value = response.data.data
                pageMode.value = 'detail'
            } else {
                ElMessage.error(response.data.message)
            }
        })
}

// 关闭文章
function closeDetail() {
    pageMode.value = 'list'
}

// 添加文章
function addArticle() {
    pageMode.value = 'add'
    articleDetail.value = {...emptyArticleDetail}
    resetEdit()
}

// 加载文章列表
function loadArticles(isRestPage = true) {
    articlesLoading.value = true
    let params = {
        searchStr: searchStr.value,
        searchTags: searchTags.value + '',
        currentPage: isRestPage ? 0 : currentPage.value,
        pageSize: pageSize.value,
        onlyMine: listMode.value == 'mine',
        inDraft: listMode.value == 'draft',
        isLock: listMode.value == 'lock',
    }
    myAxios.get('/article/list', {params: params})
        .then((response: any) => {
            if (response.data.code == 0) {
                articles.value = response.data.data.records
                currentPage.value = response.data.data.current
                totalCount.value = response.data.data.total
            } else {
                ElMessage.error(response.data.message)
            }
        })
        .finally(() => {
            articlesLoading.value = false
        })
}

// 页大小变化
function pageSizeChange(size: number) {
    pageSize.value = size
    loadArticles()
}

// 当前页变化
function currentPageChange(current: number) {
    currentPage.value = current
    loadArticles()
}

// 文章列表获取模式变更
function listModeChange() {
    loadArticles(true)
}


// 查询草稿数量
function loadDraftCount() {
    draftCount.value = 0
    if (checkPermission('article:write')) {
        myAxios.get('/article/draft-count')
            .then((response: any) => {
                if (response.data.code == 0) {
                    draftCount.value = response.data.data
                } else {
                    ElMessage.error(response.data.message)
                }
            })
    }
}

// ====================================== 搜索栏 ===========================================

const searchTags = ref<Array<string>>([])
const searchTagInputVisible = ref(false)
const searchTagInputValue = ref('')
const searchTagInputRef = ref<InstanceType<typeof ElInput>>()
const searchStr = ref('')

// 展示标签输入
function showSearchTagInput() {
    searchTagInputVisible.value = true
    nextTick(() => {
        searchTagInputRef.value!.input!.focus()
    })
}

// 提交标签输入
function searchTagInputConfirm() {
    if (searchTagInputValue.value) {
        addSearchTag(searchTagInputValue.value)
    }
    searchTagInputVisible.value = false
    searchTagInputValue.value = ''
}

// 添加标签
function addSearchTag(tag: string) {
    if (searchTags.value.indexOf(tag) < 0) {
        searchTags.value.push(tag)
        // 触发加载
        loadArticles()
    }
}

// 删除标签
function closeSearchTag(tag: string) {
    searchTags.value.splice(searchTags.value.indexOf(tag), 1)
    // 触发加载
    loadArticles()
}

// 清空标签
function clearSearchTag() {
    searchTags.value = []
    // 触发加载
    loadArticles()
}

// ====================================== 文章详情 ===========================================

// 文章详情
const articleDetail = ref<ArticleDetail>({...emptyArticleDetail})

// 打开编辑
function editArticle() {
    pageMode.value = 'edit'
    resetEdit()
}

// 删除文章
function removeArticle() {
    ElMessageBox.confirm(
        '是否确认删除文章:' + articleDetail.value.title,
        '删除',
        {
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            type: 'warning',
        }
    ).then(() => {
        // 删除权限
        myAxios.post('/article/remove', {id: articleDetail.value.id})
            .then((response) => {
                    if (response.data.code == 0) {
                        ElMessage.success("删除成功")
                        loadArticles(false)
                        loadDraftCount()
                        pageMode.value = 'list'
                    } else {
                        ElMessage.error(response.data.message)
                    }
                }
            )
    }).catch((e: any) => {
        console.log("取消 e:" + e)
    })
}

// 锁定/解锁文章
function lockArticle() {
    // 删除权限
    let params = {
        id: articleDetail.value.id,
        isLock: !articleDetail.value.isLock
    }
    myAxios.post('/article/lock', params)
        .then((response) => {
                if (response.data.code == 0) {
                    ElMessage.success("操作成功")
                    articleDetail.value.isLock = response.data.data
                    loadArticles(false)
                } else {
                    ElMessage.error(response.data.message)
                }
            }
        )
}

// ====================================== 添加/编辑 ===========================================

const articleDetailEditRef = ref<FormInstance>()

// 编辑中的文章详情
const articleDetailEdit = ref<ArticleDetail>({...emptyArticleDetail})

// 重置编辑的文章详情
function resetEdit() {
    articleDetailEditRef.value?.clearValidate()
    articleDetailEdit.value = {...articleDetail.value}
    articleDetailEdit.value.tagList = [...articleDetail.value.tagList]
}

// 关闭编辑
function closeEdit() {
    if (checkChange()) {
        ElMessageBox.confirm(
            '有未保存的修改，是否仍要退出',
            '退出编辑',
            {
                confirmButtonText: '不保存并退出',
                confirmButtonClass: 'el-button--danger',
                cancelButtonText: '取消',
                type: 'warning',
            }
        ).then(() => {
            pageMode.value = pageMode.value == 'edit' ? 'detail' : 'list'
        }).catch((e: any) => {
            console.log("取消 e:" + e)
        })
    } else {
        pageMode.value = pageMode.value == 'edit' ? 'detail' : 'list'
    }
}

// 编辑内容保存
function saveArticle(_saveText: string, _saveHtml: string) {
    articleDetailEditRef.value?.validate((valid, _field) => {
        if (valid) {
            if (checkChange()) {
                let apiUrl = articleDetailEdit.value.id ? '/article/edit/save' : '/article/add/save'
                let params = {...articleDetailEdit.value}
                myAxios.post(apiUrl, params)
                    .then((response: any) => {
                        if (response.data.code == 0) {
                            ElMessage.success("保存成功")
                            // 更新
                            articleDetailEdit.value.id = articleDetailEdit.value.id ? articleDetailEdit.value.id : response.data.data
                            articleDetail.value = articleDetailEdit.value
                            // 重新加载文章列表
                            loadArticles(pageMode.value == 'add')
                            // 重新检查草稿数量
                            loadDraftCount()
                        } else {
                            ElMessage.error(response.data.message)
                        }
                    })
            } else {
                ElMessage.success("保存成功")
            }
        }
    })
}

// 发布
function publishArticle() {
    let apiUrl = articleDetailEdit.value.id ? '/article/edit/publish' : '/article/add/publish'
    let params = {...articleDetailEdit.value}
    myAxios.post(apiUrl, params)
        .then((response: any) => {
            if (response.data.code == 0) {
                ElMessage.success("发布成功")
                // 更新
                articleDetailEdit.value.id = articleDetailEdit.value.id ? articleDetailEdit.value.id : response.data.data
                articleDetailEdit.value.isPublish = true
                articleDetail.value = articleDetailEdit.value
                // 重新加载文章列表
                loadArticles(pageMode.value == 'add')
                // 重新检查草稿数量
                loadDraftCount()
            } else {
                ElMessage.error(response.data.message)
            }
        })
}

// 检查是否编辑
function checkChange() {
    return articleDetail.value.title != articleDetailEdit.value.title
        || !compareArray(articleDetail.value.tagList ?? [], articleDetailEdit.value.tagList ?? [])
        || articleDetail.value.content != articleDetailEdit.value.content
}

// 表单校验规则
const articleDetailEditRules = ref<FormRules>({
    title: [
        {required: true, message: "请输入标题", trigger: "blur"},
        {min: 2, max: 32, message: "长度限制为2-32字符", trigger: "blur"},
    ],
    tags: [
        {validator: editTagsValidate},
    ]
})

// 标签校验规则
function editTagsValidate(_rule: any, _value: any, callback: any) {
    if (articleDetailEdit.value.tagList.length > 5) {
        callback(new Error('标签数量不可大于5个'))
    } else {
        callback()
    }
}

// ====================================== 编辑页标签 ===========================================

const editTagInputVisible = ref(false)
const editTagInputValue = ref('')
const editTagInputRef = ref<InstanceType<typeof ElInput>>()

// 展示标签输入
function showEditTagInput() {
    editTagInputVisible.value = true
    nextTick(() => {
        editTagInputRef.value!.input!.focus()
    })
}

// 提交标签输入
function editTagInputConfirm() {
    if (editTagInputValue.value) {
        addEditTag(editTagInputValue.value)
    }
    editTagInputVisible.value = false
    editTagInputValue.value = ''
}

// 添加标签
function addEditTag(tag: string) {
    if (articleDetailEdit.value.tagList) {
        if (articleDetailEdit.value.tagList.indexOf(tag) < 0) {
            articleDetailEdit.value.tagList.push(tag)
            // 手动验证
            articleDetailEditRef.value?.validateField('tags')
        }
    }
}

// 删除标签
function closeEditTag(tag: string) {
    if (articleDetailEdit.value.tagList) {
        articleDetailEdit.value.tagList.splice(articleDetailEdit.value.tagList.indexOf(tag), 1)
        // 手动验证
        articleDetailEditRef.value?.validateField('tags')
    }
}

// ====================================== 工具 ===========================================

const loginContext = useLoginStore()

// 比较数组是否相等
function compareArray(arr1: Array<any>, arr2: Array<any>) {
    if (arr1.length != arr2.length) {
        return false
    } else {
        for (let i = 0; i < arr1.length; i++) {
            if (arr1[i] != arr2[i]) {
                return false
            }
        }
        return true
    }
}

// 检查作者是否当前用户
function checkWriter(writerId: number) {
    return loginContext.userId == writerId
}

</script>

<style scoped>

.el-page-header {
    margin-bottom: 10px;
}

.el-table {
    margin: 10px 0;
}

.el-tag {
    margin: 5px;
}

</style>